home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 25
/
Aminet 25 (1998)(GTI - Schatztruhe)[!][Jun 1998].iso
/
Aminet
/
util
/
arc
/
mpackWOS.lha
/
mpackppc
/
src
/
macbhex.c
< prev
next >
Wrap
C/C++ Source or Header
|
1998-04-08
|
9KB
|
311 lines
/* macbhex.c -- simple binhex decoding routine */
/* (C) Copyright 1993,1994 by Carnegie Mellon University
* All Rights Reserved.
*
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without
* fee, provided that the above copyright notice appear in all copies
* and that both that copyright notice and this permission notice
* appear in supporting documentation, and that the name of Carnegie
* Mellon University not be used in advertising or publicity
* pertaining to distribution of the software without specific,
* written prior permission. Carnegie Mellon University makes no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied
* warranty.
*
* CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
* THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
* SOFTWARE.
*/
#include <stdio.h>
#include <ctype.h>
#include <memory.h>
#include "part.h"
#include "macnapp.h"
#include "macmpack.h"
/* from macos.c: */
extern void renameDescFile(char *, short, long);
char binhex_decode[256] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, -1, -1,
13, 14, 15, 16, 17, 18, 19, -1, 20, 21, -1, -1, -1, -1, -1, -1,
22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, -1,
37, 38, 39, 40, 41, 42, 43, -1, 44, 45, 46, 47, -1, -1, -1, -1,
48, 49, 50, 51, 52, 53, 54, -1, 55, 56, 57, 58, 59, 60, -1, -1,
61, 62, 63, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
};
#define BHEXVAL(c) (binhex_decode[(unsigned char) c])
typedef union {
unsigned char c[4];
unsigned long val;
} longbuf;
typedef struct {
OSType type, creator;
unsigned short flags;
long dlen, rlen;
} binhex_header;
#define STATE_START 0
#define STATE_FNAME 1
#define STATE_HEADER 2
#define STATE_HCRC 3
#define STATE_DFORK 4
#define STATE_DCRC 5
#define STATE_RFORK 6
#define STATE_RCRC 7
#define STATE_DONE 8
#define STATE_ERROR 9
typedef struct binhex_state {
short state; /* current state */
short part; /* current part number */
unsigned short CRC; /* cumulative CRC */
unsigned short fileCRC; /* CRC value from file */
longbuf octetbuf; /* buffer for decoded 6-bit values */
short octetin; /* current input position in octetbuf */
short donepos; /* ending position in octetbuf */
short inCRC; /* flag set when reading a CRC */
long count; /* generic counter */
FILE *outfile; /* output file */
short marker; /* flag indicating maker */
unsigned char rlebuf; /* buffer for last run length encoding value */
PCstr namebuf[65]; /* buffer for binhex filename */
binhex_header head; /* buffer for header */
FSSpec fspec; /* output file */
} binhex_state;
/* global state */
static binhex_state bh;
/* process a binhex character
*/
static void binhex_process(struct part *inpart)
{
unsigned short tmpcrc, cval;
unsigned char ctmp, c = bh.rlebuf;
StandardFileReply reply;
FInfo finfo;
char buf[256];
/* do CRC */
ctmp = bh.inCRC ? c : 0;
cval = bh.CRC & 0xf000;
tmpcrc = ((unsigned short) (bh.CRC << 4) | (ctmp >> 4))
^ (cval | (cval >> 7) | (cval >> 12));
cval = tmpcrc & 0xf000;
bh.CRC = ((unsigned short) (tmpcrc << 4) | (ctmp & 0x0f))
^ (cval | (cval >> 7) | (cval >> 12));
/* handle state */
switch (bh.state) {
case STATE_START:
bh.state = STATE_FNAME;
bh.count = 1;
*bh.namebuf = (c & 63);
break;
case STATE_FNAME:
bh.namebuf[bh.count] = c;
if (bh.count++ > *bh.namebuf) {
bh.state = STATE_HEADER;
bh.count = 0;
}
break;
case STATE_HEADER:
((char *)&bh.head)[bh.count] = c;
if (++bh.count == 18) {
bh.state = STATE_HCRC;
bh.inCRC = 1;
bh.count = 0;
}
break;
case STATE_DFORK:
case STATE_RFORK:
putc(c, bh.outfile);
if (--bh.count == 0) {
fclose(bh.outfile);
bh.outfile = NULL;
++bh.state;
bh.inCRC = 1;
}
break;
case STATE_HCRC:
case STATE_DCRC:
case STATE_RCRC:
if (!bh.count++) {
bh.fileCRC = (unsigned short) c << 8;
} else {
if ((bh.fileCRC | c) != bh.CRC) {
if (bh.state > STATE_HCRC) {
HDelete(bh.fspec.vRefNum, bh.fspec.parID, bh.fspec.name);
SetCursor(&arrow);
yell("BinHex file corrupted in transit");
SetCursor(&watch);
}
bh.state = STATE_ERROR;
break;
}
bh.CRC = 0;
if (++bh.state == STATE_DONE) {
finfo.fdType = bh.head.type;
finfo.fdCreator = bh.head.creator;
finfo.fdFlags = bh.head.flags & 0xf800;
HSetFInfo(bh.fspec.vRefNum, bh.fspec.parID, bh.fspec.name, &finfo);
PtoCstr(bh.fspec.name);
renameDescFile((char *)bh.fspec.name, bh.fspec.vRefNum, bh.fspec.parID);
break;
}
bh.count = bh.head.rlen;
if (bh.state == STATE_DFORK) {
/* prompt user */
sprintf(buf, "Saving BinHex file %s", C(bh.namebuf));
chat(buf);
SetCursor(&arrow);
NAputFile("\pSave decoded BinHex file as:", P(bh.namebuf), &reply);
SetCursor(&watch);
statrefresh();
if (!reply.sfGood) {
didchat = -1;
bh.state = STATE_ERROR;
} else {
bh.fspec = reply.sfFile;
HCreate(bh.fspec.vRefNum, bh.fspec.parID, bh.fspec.name,
bh.head.creator, bh.head.type);
bh.count = bh.head.dlen;
}
}
if (bh.count) {
bh.inCRC = 0;
bh.outfile = Macopen(inpart->infile, bh.fspec.name, bh.fspec.vRefNum,
bh.fspec.parID, 1, bh.state == STATE_DFORK ? 0 : 1, fsWrPerm);
if (!bh.outfile) {
bh.state = STATE_ERROR;
HDelete(bh.fspec.vRefNum, bh.fspec.parID, bh.fspec.name);
SetCursor(&arrow);
yell("Failed to open file for writing");
SetCursor(&watch);
}
} else {
++bh.state;
}
}
break;
}
}
/*
* decode a binhex file
* returns -1 on fatal error, 0 for continue, 1 for done
*/
int os_binhex(struct part *inpart, int part, int nparts)
{
long val;
int c;
char *bptr;
short octetpos;
static char buf[1024];
/* reset state */
if (part == 1) {
bh.state = STATE_START;
bh.part = 0;
bh.CRC = 0;
bh.octetbuf.val = 0;
bh.octetin = 26;
bh.donepos = 3;
bh.inCRC = 0;
bh.outfile = NULL;
bh.marker = 0;
}
if (++bh.part != part) bh.state = STATE_ERROR;
/* do nothing on error/completion */
if (!inpart) {
if (bh.state < STATE_DONE) bh.state = STATE_ERROR;
} else {
/* skip blank lines */
do {
if (part_gets(buf, sizeof (buf), inpart) == NULL) return (0);
} while (*buf == '\n');
bptr = buf;
if (part == 1 && *bptr++ != ':') bh.state = STATE_ERROR;
/* line reading loop */
do {
/* check line for separator */
if (!strncmp(buf, "--- ", 4)) break;
buf[strlen(buf) - 1] = '\0';
/* loop through line of binhex charaters */
while (bh.state < STATE_DONE) {
/* fill in octetbuf */
do {
if ((val = BHEXVAL(*bptr++)) == -1) {
if (bptr[-1]) {
--bh.donepos;
if (bh.octetin >= 14) --bh.donepos;
if (bh.octetin >= 20) --bh.donepos;
}
break;
}
bh.octetbuf.val |= val << bh.octetin;
} while ((bh.octetin -= 6) > 2);
if (!bptr[-1]) break;
/* handle decoded characters -- run length encoding (rle) detection */
for (octetpos = 0; octetpos < bh.donepos; ++octetpos) {
/* get character & handle rle */
c = bh.octetbuf.c[octetpos];
if (c == 0x90 && !bh.marker++) continue;
if (bh.marker) {
if (c == 0) {
bh.rlebuf = 0x90;
binhex_process(inpart);
} else {
while (--c > 0) {
binhex_process(inpart);
}
}
bh.marker = 0;
} else {
bh.rlebuf = (unsigned char) c;
binhex_process(inpart);
}
if (bh.state >= STATE_DONE) break;
}
if (bh.donepos < 3 && bh.state < STATE_DONE) bh.state = STATE_ERROR;
bh.octetin = 26;
bh.octetbuf.val = 0;
}
} while (bh.state < STATE_DONE && part_gets(bptr = buf, sizeof (buf), inpart) != NULL);
}
/* error clean up */
if (bh.state == STATE_ERROR && bh.outfile) {
fclose(bh.outfile);
bh.outfile = NULL;
HDelete(bh.fspec.vRefNum, bh.fspec.parID, bh.fspec.name);
}
return (bh.state == STATE_ERROR ? 1 : 0);
}